#pragma once

#include "png8cropfx.h"

#include "imgsource.h"
#include "cropctx.h"

#include "mnu_parser.h"

namespace png8crop
{
	static const int BASIC_PALETTE_SIZE = 16;

	static const int SCHEME_NUM_MAX = 4;

	static const int PALSET_PER_SCHEME = 2;
	static const int PALSET_PER_SCHEME_IND = 1;
	static const int COLORREF_PER_PALSET = 4;
	static const int COLORREF_PER_PALSET_IND = 2;
	
	static const int COLORREF_PER_SCHEME = COLORREF_PER_PALSET * PALSET_PER_SCHEME;
	static const int COLORREF_PER_SCHEME_IND = PALSET_PER_SCHEME_IND + COLORREF_PER_PALSET_IND;

	static const int PNG_PALETTE_SIZE = SCHEME_NUM_MAX * COLORREF_PER_SCHEME;

	static const int PLANES_PER_IMAGE = 3;
	static const long ALIGN32_MASK = 0x1f;
	static const long ALIGN16_MASK = 0x0f;
	static const long ALIGN8_MASK = 0x07;


	union yuv601_color
	{
		struct{
			unsigned char x, y, cr, cb;
		};
		struct{
			png_byte a;
			png_color rgb;
		};
		unsigned char bytes[4];
	};

	union basic_palette
	{
		png_color color[BASIC_PALETTE_SIZE];
		png_byte bytes[BASIC_PALETTE_SIZE * sizeof(png_color)];
	};

	struct palette_refer
	{
		png_byte color_id;
		png_byte opacity;
	};

	struct palette_refer8
	{
		png_byte color_id;
		png_byte opacity;
	public:
		inline palette_refer to_referer16()
		{
			palette_refer ret;
			ret.color_id = this->color_id;
			ret.opacity = this->opacity;
			ret.opacity += (ret.opacity << 4);

			return ret;
		}
	};

	union scheme_palette_set
	{
		struct{
			palette_refer8 b, p, e1, e2;
		};
		palette_refer8 all[COLORREF_PER_PALSET];
	};

	union scheme
	{
		struct {
			scheme_palette_set onSel, onAct;
		};
		scheme_palette_set all[PALSET_PER_SCHEME];
	};

	struct scheme_table
	{
		basic_palette palette;
		union
		{
			scheme schemes[SCHEME_NUM_MAX];
			struct
			{
				scheme und, csm1, csm2, csm3;
			};
		};
	};

	//input cropping

	struct schemed_crop
	{
		int scheme_id;
		crop crop;
	};

	class dib4source:
		public imgsource
	{
	private:
		png_colorp palbuf_alloc;
		png_bytep tranbuf_alloc;
		png_bytep pixbuf_alloc;

		scheme_table schemes;
		png_uint_32 plane_height;
		png_bytepp pixrows_alloc;

		png_bytep pixels;
		png_uint_32 scan_width;

	public:
		dib4source(FILE* dibsrc);
		~dib4source();

		void load_palette(FILE* clbsrc, FILE* csmsrc);
		void update_crop_scheme(schemed_crop *crop_info, int num_scheme);

		//png_uint_32 get_plane_height() {}
		size2d get_plane_size() { size2d ret = { this->size.w, this->plane_height }; return ret; }
		int get_ratio_type() { return (this->size.w / (float) this->plane_height > 1.4f) ? 1 : 2; }

	private:
		void load_dib(FILE* dibsrc);
		static void yuv601torgb(__m128i *yuv);
		void release();
	};
}